/*
 *
 * Copyright(c) 2010 Safelayer Secure Communications
 *
 * This is open source software, placed under the terms of the
 * GNU GENERAL PUBLIC LICENSE Version 3.
 * Please see: http://www.gnu.org/licenses/gpl-3.0.txt
 * 
 * Permission to use, copy, modify, and distribute this software
 * for any purpose and without fee is hereby granted, provided
 * that the above copyright notices appear in all copies and that
 * both the copyright notice and this permission notice appear in
 * supporting documentation.
 * 
 */
package com.neuralnoise.foaf.core;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;


/**
 * Models a FOAF Person. The <code>Person</code> class represents people. Something is a
 * <code>Person</code> if it is a person. We don't nitpic about whether they're alive, dead, real,
 * or imaginary. The <code>Person</code> class is a sub-class of the {@link Agent} class, since all
 * people are considered 'agents' in FOAF.
 * <p>
 * For more info see FOAF Vocabulary Specification
 * 
 * @author victor.martinez <swtp@safelayer.com>
 */
public class Person extends Agent implements Spatial {

	private Set<Document> schoolHomePageSet = new LinkedHashSet<Document>();

	private Set<String> firstNameSet = new LinkedHashSet<String>();

	private Set<String> familyNameSet = new LinkedHashSet<String>();

	private Set<Person> knowsSet = new LinkedHashSet<Person>();

	private Set<Thing> currentProjectSet = new LinkedHashSet<Thing>();

	private Set<Image> imgSet = new LinkedHashSet<Image>();

	private Set<String> planSet = new LinkedHashSet<String>();

	private Set<Document> workInfoHomepageSet = new LinkedHashSet<Document>();

	private Set<Thing> pastProjectSet = new LinkedHashSet<Thing>();

	private Set<String> surnameSet = new LinkedHashSet<String>();

	private Set<Document> interestSet = new LinkedHashSet<Document>();

	private Set<Document> publicationsSet = new LinkedHashSet<Document>();

	private Set<Document> workplaceHomepageSet = new LinkedHashSet<Document>();

	private Set<String> lastNameSet = new LinkedHashSet<String>();

	private Set<String> givenNameSet = new LinkedHashSet<String>();

	private Set<String> nicknameSet = new LinkedHashSet<String>();

	private Set<String> phoneSet = new LinkedHashSet<String>();

	private Set<String> titleSet = new LinkedHashSet<String>();

	private Set<MyersBriggsType> myersBriggsSet = new LinkedHashSet<MyersBriggsType>();

	private SpatialThing baseNear;

	public SpatialThing getBaseNear() {
		return baseNear;
	}

	public void setBaseNear(SpatialThing baseNear) {
		this.baseNear = baseNear;
	}

	public Person(String uri) {
		super(uri);
	}

	public Person() {
		super(null);
	}

	/**
	 * Returns all school home pages.
	 * 
	 * @return Returns all school home pages.
	 */
	public List<Document> getAllSchoolHomePages() {
		return new ArrayList<Document>(schoolHomePageSet);
	}

	/**
	 * Removes all of the school home pages from this {@link Person}. The school home page from
	 * <code>Person</code> will be empty after this call returns.
	 */
	public void clearSchoolHomePages() {
		schoolHomePageSet.clear();
	}

	/**
	 * Adds the specified <code>schoolHomePage</code> to this {@link Person} if it is not already
	 * present.
	 * 
	 * @param schoolHomePage The <code>schoolHomePage</code> to be added to this <code>Person</code>
	 * @return <tt>true</tt> if the <code>Person</code> did not already contain the specified
	 *         <code>schoolHomePage</code>.
	 */
	public boolean addSchoolHomePage(Document schoolHomePage) {
		return schoolHomePageSet.add(schoolHomePage);
	}

	/**
	 * Removes the specified <code>schoolHomePage</code> from this {@link Person}, if it is present.
	 * Returns <tt>true</tt> if this <code>Person</code> contained the specified
	 * <code>schoolHomepage</code> (or equivalently, if this <code>Person</code> changed as a result
	 * of the call).
	 * 
	 * @param schoolHomePage The <code>schoolHomePage</code> to be removed from this <code>Person</code>.
	 * @return <tt>true</tt> if this <code>Person</code> contained the specified
	 *         <code>schoolHomePage</code>.
	 */
	public boolean removeSchoolHomePage(Document schoolHomePage) {
		return schoolHomePageSet.remove(schoolHomePage);
	}

	/**
	 * Returns <tt>true</tt> if this {@link Person} contains the specified schoolHomePage.
	 * 
	 * @param schoolHomePage The <code>schoolHomePage</code> whose presence in this
	 *            <code>Person</code> is to be tested.
	 * @return <tt>true</tt> if this <code>Person</code> contains the specified
	 *         <code>schoolHomePage</code>.
	 */
	public boolean containsSchoolHomePage(Document schoolHomePage) {
		return schoolHomePageSet.contains(schoolHomePage);
	}

	/**
	 * Returns all firstNames.
	 * 
	 * @return Returns all firstNames.
	 */
	public List<String> getAllFirstNames() {
		return new ArrayList<String>(firstNameSet);
	}

	/**
	 * Adds the specified <code>firstName</code> to this {@link Person} if it is not already
	 * present.
	 * 
	 * @param firstName The <code>firstName</code> to be added to this <code>Person</code>.
	 * @return <tt>true</tt> if the <code>Person</code>. did not already contain the specified
	 *         <code>firstName</code>.
	 */
	public boolean addFirstName(String firstName) {
		return firstNameSet.add(firstName);
	}

	/**
	 * Removes the specified firstName from this {@link Person}, if it is present. Returns
	 * <tt>true</tt> if this <code>Person</code> contained the specified firstName (or equivalently,
	 * if this <code>Person</code> changed as a result of the call).
	 * 
	 * @param value The firstName to be removed from this <code>Person</code>.
	 * @return <tt>true</tt> if this <code>Person</code> contained the specified firstName.
	 */
	public boolean removeFirstName(String value) {
		return firstNameSet.remove(value);
	}

	/**
	 * Removes all of the firstNames from this {@link Person}. The firstNames from
	 * <code>Person</code> will be empty after this call returns.
	 */
	public void clearFirstNames() {
		firstNameSet.clear();
	}

	/**
	 * Returns <tt>true</tt> if this {@link Person} contains the specified <code>firstName</code>.
	 * 
	 * @param firstName The <code>firstName</code> whose presence in this <code>Person</code> is to
	 *            be tested.
	 * @return <tt>true</tt> if this <code>Person</code> contains the specified
	 *         <code>firstName</code>.
	 */
	public boolean containsFirstName(String firstName) {
		return firstNameSet.contains(firstName);
	}

	/**
	 * Returns all familyNames.
	 * 
	 * @return Returns all familyNames.
	 */
	public List<String> getAllFamilyNames() {
		return new ArrayList<String>(familyNameSet);
	}

	/**
	 * Adds the specified <code>familyName</code> to this {@link Person} if it is not already
	 * present.
	 * 
	 * @param familyName The <code>familyName</code> to be added to this <code>Person</code>.
	 * @return <tt>true</tt> if the <code>Person</code>. did not already contain the specified
	 *         <code>familyName</code>.
	 */
	public boolean addFamilyName(String familyName) {
		return familyNameSet.add(familyName);
	}

	/**
	 * Removes the specified familyName from this {@link Person}, if it is present. Returns
	 * <tt>true</tt> if this <code>Person</code> contained the specified familyName (or
	 * equivalently, if this <code>Person</code> changed as a result of the call).
	 * 
	 * @param value The familyName to be removed from this <code>Person</code>.
	 * @return <tt>true</tt> if this <code>Person</code> contained the specified familyName.
	 */
	public boolean removeFamilyName(String value) {
		return familyNameSet.remove(value);
	}

	/**
	 * Removes all of the familyNames from this {@link Person}. The familyNames from
	 * <code>Person</code> will be empty after this call returns.
	 */
	public void clearFamilyNames() {
		familyNameSet.clear();
	}

	/**
	 * Returns <tt>true</tt> if this {@link Person} contains the specified <code>familyName</code>.
	 * 
	 * @param familyName The <code>familyName</code> whose presence in this <code>Person</code> is
	 *            to be tested.
	 * @return <tt>true</tt> if this <code>Person</code> contains the specified
	 *         <code>familyName</code>.
	 */
	public boolean containsFamilyName(String familyName) {
		return familyNameSet.contains(familyName);
	}

	/**
	 * Returns all currentProjects.
	 * 
	 * @return Returns all currentProjects.
	 */
	public List<Thing> getAllCurrentProjects() {
		return new ArrayList<Thing>(currentProjectSet);
	}
	
	public List<Thing> getAllLocations() {
		List<Thing> ret = new ArrayList<Thing>();
		ret.add(baseNear);
		return ret;
	}

	/**
	 * Adds the specified <code>currentProject</code> to this {@link Person} if it is not already
	 * present.
	 * 
	 * @param currentProject The <code>currentProject</code> to be added to this <code>Person</code>
	 *            .
	 * 
	 * @return <tt>true</tt> if the <code>Person</code>. did not already contain the specified
	 *         <code>currentProject</code>.
	 */
	public boolean addCurrentProject(Thing currentProject) {
		return currentProjectSet.add(currentProject);
	}

	/**
	 * Removes the specified currentProject from this {@link Person}, if it is present. Returns
	 * <tt>true</tt> if this <code>Person</code> contained the specified currentProject (or
	 * equivalently, if this <code>Person</code> changed as a result of the call).
	 * 
	 * @param currentProject The currentProject to be removed from this <code>Person</code>.
	 * @return <tt>true</tt> if this <code>Person</code> contained the specified currentProject.
	 */
	public boolean removeCurrentProject(Thing currentProject) {
		return currentProjectSet.remove(currentProject);
	}

	/**
	 * Removes all of the currentProjects from this {@link Person}. The currentProjects from
	 * <code>Person</code> will be empty after this call returns.
	 */
	public void clearCurrentProjects() {
		currentProjectSet.clear();
	}

	/**
	 * Returns <tt>true</tt> if this {@link Person} contains the specified
	 * <code>currentProject</code>.
	 * 
	 * @param currentProject The <code>currentProject</code> whose presence in this
	 *            <code>Person</code> is to be tested.
	 * @return <tt>true</tt> if this <code>Person</code> contains the specified
	 *         <code>currentProject</code>.
	 */
	public boolean containsCurrentProject(Thing currentProject) {
		return currentProjectSet.contains(currentProject);
	}

	/**
	 * Returns all myersBriggs.
	 * 
	 * @return Returns all myersBriggs.
	 */
	public List<MyersBriggsType> getAllMyersBriggs() {
		return new ArrayList<MyersBriggsType>(myersBriggsSet);
	}

	/**
	 * Adds the specified <code>myersBriggs</code> to this {@link Person} if it is not already
	 * present.
	 * 
	 * @param myersBriggs The <code>myersBriggs</code> to be added to this <code>Person</code> .
	 * 
	 * @return <tt>true</tt> if the <code>Person</code>. did not already contain the specified
	 *         <code>myersBriggs</code>.
	 */
	public boolean addMyersBriggs(MyersBriggsType myersBriggs) {
		return myersBriggsSet.add(myersBriggs);
	}

	/**
	 * Removes the specified myersBriggs from this {@link Person}, if it is present. Returns
	 * <tt>true</tt> if this <code>Person</code> contained the specified myersBriggs (or
	 * equivalently, if this <code>Person</code> changed as a result of the call).
	 * 
	 * @param myersBriggs The myersBriggs to be removed from this <code>Person</code>.
	 * @return <tt>true</tt> if this <code>Person</code> contained the specified myersBriggs.
	 */
	public boolean removeMyersBriggs(MyersBriggsType myersBriggs) {
		return myersBriggsSet.remove(myersBriggs);
	}

	/**
	 * Removes all of the myersBriggs from this {@link Person}. The myersBriggs from
	 * <code>Person</code> will be empty after this call returns.
	 */
	public void clearMyersBriggs() {
		myersBriggsSet.clear();
	}

	/**
	 * Returns <tt>true</tt> if this {@link Person} contains the specified <code>myersBriggs</code>.
	 * 
	 * @param myersBriggs The <code>myersBriggs</code> whose presence in this <code>Person</code> is
	 *            to be tested.
	 * @return <tt>true</tt> if this <code>Person</code> contains the specified
	 *         <code>myersBriggs</code>.
	 */
	public boolean containsMyersBriggs(MyersBriggsType myersBriggs) {
		return myersBriggsSet.contains(myersBriggs);
	}

	/**
	 * Returns the latitude.
	 * 
	 * @return the latitude.
	 * @throws IllegalStateException if the attribute <code>baseNear</code> is <code>null</code>.
	 */
	public BigDecimal getLatitude() {
		if (baseNear == null)
			throw new IllegalStateException("baseNear attribute is not already initialized");
		else
			return baseNear.getLatitude();
	}

	/**
	 * Set the latitude.
	 * 
	 * @param latitude the latitude to set.
	 */
	public void setLatitude(BigDecimal latitude) {
		// lazy initialization
		if (baseNear == null)
			baseNear = new SpatialThing();

		baseNear.setLatitude(latitude);
	}

	/**
	 * Returns the longitude.
	 * 
	 * @return the longitude.
	 * @throws IllegalStateException if the attribute <code>baseNear</code> is <code>null</code>.
	 */
	public BigDecimal getLongitude() {
		if (baseNear == null)
			throw new IllegalStateException("baseNear attribute is not already initialized");
		else
			return baseNear.getLongitude();
	}

	/**
	 * Set the longitude.
	 * 
	 * @param longitude the longitude to set.
	 */
	public void setLongitude(BigDecimal longitude) {
		// lazy initialization
		if (baseNear == null)
			baseNear = new SpatialThing();

		baseNear.setLongitude(longitude);
	}

	/**
	 * Return the altitude.
	 * 
	 * @return the altitude.
	 * @throws IllegalStateException if the attribute <code>baseNear</code> is <code>null</code>.
	 */
	public BigDecimal getAltitude() {
		if (baseNear == null)
			throw new IllegalStateException("baseNear attribute is not already initialized");
		else
			return baseNear.getAltitude();
	}

	/**
	 * Set the altitude.
	 * 
	 * @param altitude the altitude to set.
	 */
	public void setAltitude(BigDecimal altitude) {
		// lazy initialization
		if (baseNear == null)
			baseNear = new SpatialThing();

		baseNear.setAltitude(altitude);
	}

	/**
	 * Return all imgs.
	 * 
	 * @return Returns all imgs.
	 */
	public List<Image> getAllImgs() {
		return new ArrayList<Image>(imgSet);
	}

	/**
	 * Adds the specified <code>img</code> to this {@link Person} if it is not already present.
	 * 
	 * @param img The <code>img</code> to be added to this <code>Person</code>.
	 * 
	 * @return <tt>true</tt> if the <code>Person</code>. did not already contain the specified
	 *         <code>img</code>.
	 */
	public boolean addImg(Image img) {
		return imgSet.add(img);
	}

	/**
	 * Removes the specified img from this {@link Person}, if it is present. Returns <tt>true</tt> if
	 * this <code>Person</code> contained the specified img (or equivalently, if this
	 * <code>Person</code> changed as a result of the call).
	 * 
	 * @param img The img to be removed from this <code>Person</code>.
	 * @return <tt>true</tt> if this <code>Person</code> contained the specified img.
	 */
	public boolean removeImg(Image img) {
		return imgSet.remove(img);
	}

	/**
	 * Removes all of the imgs from this {@link Person}. The imgs from <code>Person</code> will be
	 * empty after this call returns.
	 */
	public void clearImgs() {
		imgSet.clear();
	}

	/**
	 * Returns <tt>true</tt> if this {@link Person} contains the specified <code>img</code>.
	 * 
	 * @param img The <code>img</code> whose presence in this <code>Person</code> is to be tested.
	 * @return <tt>true</tt> if this <code>Person</code> contains the specified <code>img</code>.
	 */
	public boolean containsImg(Image img) {
		return imgSet.contains(img);
	}

	/**
	 * Returns all plans.
	 * 
	 * @return Returns all plans.
	 */
	public List<String> getAllPlans() {
		return new ArrayList<String>(planSet);
	}

	/**
	 * Adds the specified <code>plan</code> to this {@link Person} if it is not already present.
	 * 
	 * @param plan The <code>plan</code> to be added to this <code>Person</code>.
	 * 
	 * @return <tt>true</tt> if the <code>Person</code>. did not already contain the specified
	 *         <code>plan</code>.
	 */
	public boolean addPlan(String plan) {
		return planSet.add(plan);
	}

	/**
	 * Removes the specified plan from this {@link Person}, if it is present. Returns <tt>true</tt> if
	 * this <code>Person</code> contained the specified plan (or equivalently, if this
	 * <code>Person</code> changed as a result of the call).
	 * 
	 * @param plan The plan to be removed to this <code>Person</code>.
	 * @return <tt>true</tt> if this <code>Person</code> contained the specified plan.
	 */
	public boolean removePlan(String plan) {
		return planSet.remove(plan);
	}

	/**
	 * Removes all of the plans from this {@link Person}. The plans from <code>Person</code> will be
	 * empty after this call returns.
	 */
	public void clearPlans() {
		planSet.clear();
	}

	/**
	 * Returns <tt>true</tt> if this {@link Person} contains the specified <code>plans</code>.
	 * 
	 * @param plan The <code>plan</code> whose presence in this <code>Person</code> is to be tested.
	 * @return <tt>true</tt> if this <code>Person</code> contains the specified <code>plan</code>.
	 */
	public boolean containsPlan(String plan) {
		return planSet.contains(plan);
	}

	/**
	 * Returns all workInfoHomepages.
	 * 
	 * @return Returns all workInfoHomepages.
	 */
	public List<Document> getAllWorkInfoHomepages() {
		return new ArrayList<Document>(workInfoHomepageSet);
	}

	/**
	 * Adds the specified <code>workInfoHomepage</code> to this {@link Person} if it is not already
	 * present.
	 * 
	 * @param workInfoHomepage The <code>workInfoHomepage</code> to be added to this
	 *            <code>Person</code>.
	 * 
	 * @return <tt>true</tt> if the <code>Person</code>. did not already contain the specified
	 *         <code>workInfoHomepage</code>.
	 */
	public boolean addWorkInfoHomepage(Document workInfoHomepage) {
		return workInfoHomepageSet.add(workInfoHomepage);
	}

	/**
	 * Removes the specified workInfoHomepage from this {@link Person}, if it is present. Returns
	 * <tt>true</tt> if this <code>Person</code> contained the specified workInfoHomepage (or
	 * equivalently, if this <code>Person</code> changed as a result of the call).
	 * 
	 * @param workInfoHomepage The workInfoHomepage to be removed from this <code>Person</code>.
	 * @return <tt>true</tt> if this <code>Person</code> contained the specified workInfoHomepage.
	 */
	public boolean removeWorkInfoHomepage(Document workInfoHomepage) {
		return workInfoHomepageSet.remove(workInfoHomepage);
	}

	/**
	 * Removes all of the workInfoHomepages from this {@link Person}. The workInfoHomepages from
	 * <code>Person</code> will be empty after this call returns.
	 */
	public void clearWorkInfoHomepages() {
		workInfoHomepageSet.clear();
	}

	/**
	 * Returns <tt>true</tt> if this {@link Person} contains the specified
	 * <code>workInfoHomepage</code>.
	 * 
	 * @param workInfoHomepage The <code>workInfoHomepage</code> whose presence in this
	 *            <code>Person</code> is to be tested.
	 * @return <tt>true</tt> if this <code>Person</code> contains the specified
	 *         <code>workInfoHomepage</code>.
	 */
	public boolean containsWorkInfoHomepage(Document workInfoHomepage) {
		return workInfoHomepageSet.contains(workInfoHomepage);
	}

	/**
	 * Returns all pastProjects.
	 * 
	 * @return Returns all pastProjects.
	 */
	public List<Thing> getAllPastProjects() {
		return new ArrayList<Thing>(pastProjectSet);
	}

	/**
	 * Adds the specified <code>pastProject</code> to this {@link Person} if it is not already
	 * present.
	 * 
	 * @param pastProject The <code>pastProject</code> to be added to this <code>Person</code>.
	 * 
	 * @return <tt>true</tt> if the <code>Person</code>. did not already contain the specified
	 *         <code>pastProject</code>.
	 */
	public boolean addPastProject(Thing pastProject) {
		return pastProjectSet.add(pastProject);
	}

	/**
	 * Removes the specified pastProject from this {@link Person}, if it is present. Returns
	 * <tt>true</tt> if this <code>Person</code> contained the specified pastProject (or
	 * equivalently, if this <code>Person</code> changed as a result of the call).
	 * 
	 * @param pastProject The pastProject to be removed from this <code>Person</code>.
	 * @return <tt>true</tt> if this <code>Person</code> contained the specified pastProject.
	 */
	public boolean removePastProject(Thing pastProject) {
		return pastProjectSet.remove(pastProject);
	}

	/**
	 * Removes all of the pastProjects from this {@link Person}. The pastProjects from
	 * <code>Person</code> will be empty after this call returns.
	 */
	public void clearPastProjects() {
		pastProjectSet.clear();
	}

	/**
	 * Returns <tt>true</tt> if this {@link Person} contains the specified <code>pastProject</code>.
	 * 
	 * @param pastProject The <code>pastProject</code> whose presence in this <code>Person</code> is
	 *            to be tested.
	 * @return <tt>true</tt> if this <code>Person</code> contains the specified
	 *         <code>pastProject</code>.
	 */
	public boolean containsPastProject(Thing pastProject) {
		return workInfoHomepageSet.contains(pastProject);
	}

	/**
	 * Returns all surnames.
	 * 
	 * @return Returns all surnames.
	 */
	public List<String> getAllSurnames() {
		return new ArrayList<String>(surnameSet);
	}

	/**
	 * Adds the specified <code>surname</code> to this {@link Person} if it is not already present.
	 * 
	 * @param surname The <code>surname</code> to be added to this <code>Person</code>.
	 * 
	 * @return <tt>true</tt> if the <code>Person</code> did not already contain the specified
	 *         <code>surname</code>.
	 */
	public boolean addSurname(String surname) {
		return surnameSet.add(surname);
	}

	/**
	 * Removes the specified surname from this {@link Person}, if it is present. Returns <tt>true</tt>
	 * if this <code>Person</code> contained the specified surname (or equivalently, if this
	 * <code>Person</code> changed as a result of the call).
	 * 
	 * @param surname The surname to be removed from this <code>Person</code>.
	 * @return <tt>true</tt> if this <code>Person</code> contained the specified surname.
	 */
	public boolean removeSurname(String surname) {
		return surnameSet.remove(surname);
	}

	/**
	 * Removes all of the surnames from this {@link Person}. The surnames from <code>Person</code>
	 * will be empty after this call returns.
	 */
	public void clearSurnames() {
		surnameSet.clear();
	}

	/**
	 * Returns <tt>true</tt> if this {@link Person} contains the specified <code>surname</code>.
	 * 
	 * @param surname The <code>surname</code> whose presence in this <code>Person</code> is to be
	 *            tested.
	 * @return <tt>true</tt> if this <code>Person</code> contains the specified <code>surname</code>
	 *         .
	 */
	public boolean containsSurname(String surname) {
		return surnameSet.contains(surname);
	}

	/**
	 * Returns all interests.
	 * 
	 * @return Returns all interests.
	 */
	public List<Document> getAllInterests() {
		return new ArrayList<Document>(interestSet);
	}

	/**
	 * Adds the specified <code>interest</code> to this {@link Person} if it is not already present.
	 * 
	 * @param interest The <code>interest</code> to be added to this <code>Person</code>.
	 * 
	 * @return <tt>true</tt> if the <code>Person</code> did not already contain the specified
	 *         <code>interest</code>.
	 */
	public boolean addInterest(Document interest) {
		return interestSet.add(interest);
	}

	/**
	 * Removes the specified interest from this {@link Person}, if it is present. Returns
	 * <tt>true</tt> if this <code>Person</code> contained the specified interest (or equivalently,
	 * if this <code>Person</code> changed as a result of the call).
	 * 
	 * @param interest The interest to be removed from this <code>Person</code>.
	 * @return <tt>true</tt> if this <code>Person</code> contained the specified interest.
	 */
	public boolean removeInterest(Document interest) {
		return interestSet.remove(interest);
	}

	/**
	 * Removes all of the interests from this {@link Person}. The interests from <code>Person</code>
	 * will be empty after this call returns.
	 */
	public void clearInterests() {
		interestSet.clear();
	}

	/**
	 * Returns <tt>true</tt> if this {@link Person} contains the specified <code>interest</code>.
	 * 
	 * @param interest The <code>interest</code> whose presence in this <code>Person</code> is to be
	 *            tested.
	 * @return <tt>true</tt> if this <code>Person</code> contains the specified
	 *         <code>interest</code>.
	 */
	public boolean containsInterest(Document interest) {
		return interestSet.contains(interest);
	}

	/**
	 * Returns all publications.
	 * 
	 * @return Returns all publications.
	 */
	public List<Document> getAllPublications() {
		return new ArrayList<Document>(publicationsSet);
	}

	/**
	 * Adds the specified <code>publication</code> to this {@link Person} if it is not already
	 * present.
	 * 
	 * @param publication The <code>publication</code> to be added to this <code>Person</code>.
	 * 
	 * @return <tt>true</tt> if the <code>Person</code> did not already contain the specified
	 *         <code>publication</code>.
	 */
	public boolean addPublication(Document publication) {
		return publicationsSet.add(publication);
	}

	/**
	 * Removes the specified publication from this {@link Person}, if it is present. Returns
	 * <tt>true</tt> if this <code>Person</code> contained the specified publication (or
	 * equivalently, if this <code>Person</code> changed as a result of the call).
	 * 
	 * @param publication The publication to be removed from this <code>Person</code>.
	 * @return <tt>true</tt> if this <code>Person</code> contained the specified publication.
	 */
	public boolean removePublication(Document publication) {
		return publicationsSet.remove(publication);
	}

	/**
	 * Removes all of the publications from this {@link Person}. The publications from
	 * <code>Person</code> will be empty after this call returns.
	 */
	public void clearPublications() {
		publicationsSet.clear();
	}

	/**
	 * Returns <tt>true</tt> if this {@link Person} contains the specified <code>publication</code>.
	 * 
	 * @param interest The <code>publication</code> whose presence in this <code>Person</code> is
	 *            to be tested.
	 * @return <tt>true</tt> if this <code>Person</code> contains the specified
	 *         <code>publication</code>.
	 */
	public boolean containsPublication(Document interest) {
		return publicationsSet.contains(interest);
	}

	/**
	 * Returns all workplaceHomepages.
	 * 
	 * @return Returns all workplaceHomepages.
	 */
	public List<Document> getAllWorkplaceHomepages() {
		return new ArrayList<Document>(workplaceHomepageSet);
	}

	/**
	 * Adds the specified <code>workplaceHomepage</code> to this {@link Person} if it is not already
	 * present.
	 * 
	 * @param publication The <code>workplaceHomepage</code> to be added to this
	 *            <code>Person</code>.
	 * 
	 * @return <tt>true</tt> if the <code>Person</code> did not already contain the specified
	 *         <code>workplaceHomepage</code>.
	 */
	public boolean addWorkplaceHomepage(Document publication) {
		return workplaceHomepageSet.add(publication);
	}

	/**
	 * Removes the specified workplaceHomepage from this {@link Person}, if it is present. Returns
	 * <tt>true</tt> if this <code>Person</code> contained the specified workplaceHomepage (or
	 * equivalently, if this <code>Person</code> changed as a result of the call).
	 * 
	 * @param workplaceHomepage The workplaceHomepage to be removed from this <code>Person</code>.
	 * @return <tt>true</tt> if this <code>Person</code> contained the specified workplaceHomepage.
	 */
	public boolean removeWorkplaceHomepage(Document workplaceHomepage) {
		return workplaceHomepageSet.remove(workplaceHomepage);
	}

	/**
	 * Removes all of the workplaceHomepages from this {@link Person}. The workplaceHomepages from
	 * <code>Person</code> will be empty after this call returns.
	 */
	public void clearWorkplaceHomepages() {
		workplaceHomepageSet.clear();
	}

	/**
	 * Returns <tt>true</tt> if this {@link Person} contains the specified
	 * <code>workplaceHomepage</code>.
	 * 
	 * @param workplaceHomepage The <code>workplaceHomepage</code> whose presence in this
	 *            <code>Person</code> is to be tested.
	 * @return <tt>true</tt> if this <code>Person</code> contains the specified
	 *         <code>workplaceHomepage</code>.
	 */
	public boolean containsWorkplaceHomepage(Document workplaceHomepage) {
		return workplaceHomepageSet.contains(workplaceHomepage);
	}

	/**
	 * Returns all lastNames.
	 * 
	 * @return Returns all lastNames.
	 */
	public List<String> getAllLastNames() {
		return new ArrayList<String>(lastNameSet);
	}

	/**
	 * Adds the specified <code>lastName</code> to this {@link Person} if it is not already present.
	 * 
	 * @param lastName The <code>lastName</code> to be added to this <code>Person</code>.
	 * 
	 * @return <tt>true</tt> if the <code>Person</code> did not already contain the specified
	 *         <code>lastName</code>.
	 */
	public boolean addLastName(String lastName) {
		return lastNameSet.add(lastName);
	}

	/**
	 * Removes the specified lastName from this {@link Person}, if it is present. Returns
	 * <tt>true</tt> if this <code>Person</code> contained the specified lastName (or equivalently,
	 * if this <code>Person</code> changed as a result of the call).
	 * 
	 * @param lastName The lastName to be removed from this <code>Person</code>.
	 * @return <tt>true</tt> if this <code>Person</code> contained the specified lastName.
	 */
	public boolean removeLastName(String lastName) {
		return lastNameSet.remove(lastName);
	}

	/**
	 * Removes all of the lastNames from this {@link Person}. The lastName from <code>Person</code>
	 * will be empty after this call returns.
	 */
	public void clearLastNames() {
		lastNameSet.clear();
	}

	/**
	 * Returns <tt>true</tt> if this {@link Person} contains the specified <code>lastName</code>.
	 * 
	 * @param lastName The <code>lastName</code> whose presence in this <code>Person</code> is to be
	 *            tested.
	 * @return <tt>true</tt> if this <code>Person</code> contains the specified
	 *         <code>lastName</code>.
	 */
	public boolean containsLastName(String lastName) {
		return lastNameSet.contains(lastName);
	}

	/**
	 * Returns all givenNames.
	 * 
	 * @return Returns all givenNames.
	 */
	public List<String> getAllGivenNames() {
		return new ArrayList<String>(givenNameSet);
	}

	/**
	 * Adds the specified <code>givenName</code> to this {@link Person} if it is not already
	 * present.
	 * 
	 * @param givenName The <code>givenName</code> to be added to this <code>Person</code>.
	 * 
	 * @return <tt>true</tt> if the <code>Person</code> did not already contain the specified
	 *         <code>givenName</code>.
	 */
	public boolean addGivenName(String givenName) {
		return givenNameSet.add(givenName);
	}

	/**
	 * Removes the specified givenName from this {@link Person}, if it is present. Returns
	 * <tt>true</tt> if this <code>Person</code> contained the specified givenName (or equivalently,
	 * if this <code>Person</code> changed as a result of the call).
	 * 
	 * @param givenName The givenName to be removed from this <code>Person</code>.
	 * @return <tt>true</tt> if this <code>Person</code> contained the specified givenName.
	 */
	public boolean removeGivenName(String givenName) {
		return givenNameSet.remove(givenName);
	}

	/**
	 * Removes all of the givenName from this {@link Person}. The givenName from <code>Person</code>
	 * will be empty after this call returns.
	 */
	public void clearGivenNames() {
		givenNameSet.clear();
	}

	/**
	 * Returns <tt>true</tt> if this {@link Person} contains the specified <code>givenName</code>.
	 * 
	 * @param givenName The <code>givenName</code> whose presence in this <code>Person</code> is to
	 *            be tested.
	 * @return <tt>true</tt> if this <code>Person</code> contains the specified
	 *         <code>givenName</code>.
	 */
	public boolean containsGivenName(String givenName) {
		return givenNameSet.contains(givenName);
	}

	/**
	 * Returns all nicknames.
	 * 
	 * @return Returns all nicknames.
	 */
	public List<String> getAllNicknames() {
		return new ArrayList<String>(nicknameSet);
	}

	/**
	 * Adds the specified <code>nickname</code> to this {@link Person} if it is not already present.
	 * 
	 * @param nickname The <code>nickname</code> to be added to this <code>Person</code>.
	 * 
	 * @return <tt>true</tt> if the <code>Person</code> did not already contain the specified
	 *         <code>nickname</code>.
	 */
	public boolean addNickname(String nickname) {
		return nicknameSet.add(nickname);
	}

	/**
	 * Removes the specified nickname from this {@link Person}, if it is present. Returns
	 * <tt>true</tt> if this <code>Person</code> contained the specified nickname (or equivalently,
	 * if this <code>Person</code> changed as a result of the call).
	 * 
	 * @param nickname The nickname to be removed from this <code>Person</code>.
	 * @return <tt>true</tt> if this <code>Person</code> contained the specified nickname.
	 */
	public boolean removeNickname(String nickname) {
		return nicknameSet.remove(nickname);
	}

	/**
	 * Removes all of the nickname from this {@link Person}. The nickname from <code>Person</code>
	 * will be empty after this call returns.
	 */
	public void clearNicknames() {
		nicknameSet.clear();
	}

	/**
	 * Returns <tt>true</tt> if this {@link Person} contains the specified <code>nickname</code>.
	 * 
	 * @param nickname The <code>nickname</code> whose presence in this <code>Person</code> is to be
	 *            tested.
	 * @return <tt>true</tt> if this <code>Person</code> contains the specified
	 *         <code>nickname</code>.
	 */
	public boolean containsNickname(String nickname) {
		return nicknameSet.contains(nickname);
	}

	/**
	 * Returns all phones.
	 * 
	 * @return Returns all phones.
	 */
	public List<String> getAllPhones() {
		return new ArrayList<String>(phoneSet);
	}

	/**
	 * Adds the specified <code>phone</code> to this {@link Person} if it is not already present.
	 * 
	 * @param phone The <code>phone</code> to be added to this <code>Person</code>.
	 * 
	 * @return <tt>true</tt> if the <code>Person</code> did not already contain the specified
	 *         <code>phone</code>.
	 */
	public boolean addPhone(String phone) {
		return phoneSet.add(phone);
	}

	/**
	 * Removes the specified phone from this {@link Person}, if it is present. Returns <tt>true</tt>
	 * if this <code>Person</code> contained the specified phone (or equivalently, if this
	 * <code>Person</code> changed as a result of the call).
	 * 
	 * @param phone The phone to be removed from this <code>Person</code>.
	 * @return <tt>true</tt> if this <code>Person</code> contained the specified phone.
	 */
	public boolean removePhone(String phone) {
		return phoneSet.remove(phone);
	}

	/**
	 * Removes all of the phones from this {@link Person}. The phones from <code>Person</code> will
	 * be empty after this call returns.
	 */
	public void clearPhones() {
		phoneSet.clear();
	}

	/**
	 * Returns <tt>true</tt> if this {@link Person} contains the specified <code>phone</code>.
	 * 
	 * @param phone The <code>phone</code> whose presence in this <code>Person</code> is to be
	 *            tested.
	 * @return <tt>true</tt> if this <code>Person</code> contains the specified <code>phone</code>.
	 */
	public boolean containsPhone(String phone) {
		return phoneSet.contains(phone);
	}

	/**
	 * Returns all titles.
	 * 
	 * @return Returns all titles.
	 */
	public List<String> getAllTitles() {
		return new ArrayList<String>(titleSet);
	}

	/**
	 * Adds the specified <code>title</code> to this {@link Person} if it is not already present.
	 * 
	 * @param title The <code>title</code> to be added to this <code>Person</code>.
	 * 
	 * @return <tt>true</tt> if the <code>Person</code> did not already contain the specified
	 *         <code>title</code>.
	 */
	public boolean addTitle(String title) {
		return titleSet.add(title);
	}

	/**
	 * Removes the specified title from this {@link Person}, if it is present. Returns <tt>true</tt>
	 * if this <code>Person</code> contained the specified title (or equivalently, if this
	 * <code>Person</code> changed as a result of the call).
	 * 
	 * @param title The title to be removed from this <code>Person</code>.
	 * @return <tt>true</tt> if this <code>Person</code> contained the specified title.
	 */
	public boolean removeTitle(String title) {
		return titleSet.remove(title);
	}

	/**
	 * Removes all of the titles from this {@link Person}. The titles from <code>Person</code> will
	 * be empty after this call returns.
	 */
	public void clearTitles() {
		titleSet.clear();
	}

	/**
	 * Returns <tt>true</tt> if this {@link Person} contains the specified <code>title</code>.
	 * 
	 * @param title The <code>title</code> whose presence in this <code>Person</code> is to be
	 *            tested.
	 * @return <tt>true</tt> if this <code>Person</code> contains the specified <code>title</code>.
	 */
	public boolean containsTitle(String title) {
		return phoneSet.contains(title);
	}

	/**
	 * Returns all known persons.
	 * 
	 * @return Returns all known persons.
	 */
	public List<Person> getAllKnows() {
		return new ArrayList<Person>(knowsSet);
	}

	/**
	 * Adds the specified knows relationship, <code>person</code>, to this {@link Person} if 
	 * it is not already present.
	 * 
	 * @param person The knows <code>person</code> to be added to this <code>Person</code>.
	 * 
	 * @return <tt>true</tt> if the <code>Person</code> did not already contain the specified knows
	 *         <code>person</code>.
	 */
	public boolean addKnows(Person person) {
		return knowsSet.add(person);
	}

	/**
	 * Removes the specified knows person from this {@link Person}, if it is present. Returns
	 * <tt>true</tt> if this <code>Person</code> contained the specified knows person (or
	 * equivalently, if this <code>Person</code> changed as a result of the call).
	 * 
	 * @param person The person to be removed from this <code>Person</code>.
	 * @return <tt>true</tt> if this <code>Person</code> contained the specified knows person.
	 */
	public boolean removeKnows(Person person) {
		return knowsSet.remove(person);
	}

	/**
	 * Removes all of the knows persons from this {@link Person}. The knows persons from
	 * <code>Person</code> will be empty after this call returns.
	 */
	public void clearKnows() {
		knowsSet.clear();
	}

	/**
	 * Returns <tt>true</tt> if this {@link Person} contains the specified knows <code>person</code>
	 * .
	 * 
	 * @param person The knows <code>person</code> whose presence in this <code>Person</code> is to
	 *            be tested.
	 * @return <tt>true</tt> if this <code>Person</code> contains the specified knows
	 *         <code>person</code>
	 */
	public boolean containsKnows(Person person) {
		return knowsSet.contains(person);
	}

}